Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

Add tuple support in interactive prompts #1333

Merged
merged 15 commits into from
Dec 17, 2019

Conversation

spalladino
Copy link
Contributor

Fixes #1330. Tuples can be entered as comma separated, or as comma separated enclosed in parenthesis.

Screenshot from 2019-12-13 17-26-22

Copy link
Contributor

@frangio frangio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @spalladino! The logic looks solid.

@@ -66,9 +66,17 @@ export function getABIFunction(contract: Contract, methodName: string, args: any
}
}

export function getABIType(arg: any): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think InputInfo is the right type.

Suggested change
export function getABIType(arg: any): string {
export function getABIType(arg: InputInfo): string {

Also what do you think about renaming this function so that it's clear it's for display purposes? displayABIType, getABITypeDisplay, getABITypeLabel, ... Not sure. I also think it's kind of redundant for the name to say ABI, since it's the name of the module it's contained in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point on the naming. Changed it to getArgTypeLabel.

@@ -238,3 +250,35 @@ export function validateSalt(salt: string, required = false) {
throw new Error(`Invalid salt ${salt}, must be an uint256 value.`);
}
}

export function getPlaceholder(arg: Pick<MethodArg, 'type' | 'components'>): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think "placeholder" is very accurate. What about getSampleInput?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like it! The original name was placeholder because the idea was to use it as a placeholder when presenting the question, but it was after that we noted that inquirer does not support placeholders (it only displays them when they are the default value).

@@ -46,18 +48,24 @@ function quoteArguments(args: string) {
return args;
}

export function parseArg(input: string | string[], type: string): any {
export function parseArg(input: string | string[], { type, components }: Pick<MethodArg, 'type' | 'components'>): any {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the entire MethodArg type here? I imagine that using Pick simplifies the tests? Is there another reason?

If we insist on not using the entire type, I think we should define a type alias in this file. It represents an important concept, and it's used twice in the file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem was in the recursive call, since the types for an array (for example) are not named. I agree with giving it a proper name, just created MethodArgType for that.

// TODO: Handle tuples in ABI specification
// Tuples: recursively parse
if (type === 'tuple') {
const inputs = typeof input === 'string' ? parseArray(stripParens(input), '(', ')') : input;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found it weird that parseArray wouldn't handle the delimiters itself. What do you think about doing that?

Also, why do we allow the input to not be surrounded by delimiters? In what cases is that used? Does that apply to tuples in the same way that it applies to arrays?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found it weird that parseArray wouldn't handle the delimiters itself. What do you think about doing that?

Good point, I think it could be refactored. That said, given that this routine is pretty isolated (and working!), I wouldn't risk changing it now.

Also, why do we allow the input to not be surrounded by delimiters? In what cases is that used? Does that apply to tuples in the same way that it applies to arrays?

When the user is prompted to enter an array, they can just enter a comma separated list, without the brackets, for simplicity. Same applies for tuples.

@@ -59,18 +59,20 @@ function getCommandProps(
return {
...accum,
[arg.name]: {
message: arg.name ? `${arg.name} (${arg.type}):` : `(${arg.type}):`,
message: argLabel(arg),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the previous string had a colon at the end, and argLabel doesn't (which is okay because in the other place where it's used there was no colon).

Suggested change
message: argLabel(arg),
message: argLabel(arg) + ':',

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

@@ -46,18 +48,24 @@ function quoteArguments(args: string) {
return args;
}

export function parseArg(input: string | string[], type: string): any {
export function parseArg(input: string | string[], { type, components }: Pick<MethodArg, 'type' | 'components'>): any {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, in what cases is input an array?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, parseArray does not parse just the top-level arrays, but it returns arrays of arrays (as many levels deep as needed). So, the parseArg recursive call in the case of arrays may be done with an array instead of a string.

And writing this I'm thinking that maybe arrays of tuples (or viceversa) may not work...

packages/cli/src/utils/input.ts Show resolved Hide resolved
@@ -261,8 +274,10 @@ export function getPlaceholder(type: string): string {
return '0x1df62f291b2e969fb0849d99d9ce41e2f137006e';
} else if (type === 'string') {
return 'Hello world';
} else if (type === 'tuple' && components) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there cases when components is undefined?

@@ -238,3 +250,35 @@ export function validateSalt(salt: string, required = false) {
throw new Error(`Invalid salt ${salt}, must be an uint256 value.`);
}
}

export function getPlaceholder(arg: Pick<MethodArg, 'type' | 'components'>): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler isn't catching this because we're not running it in strict mode. It will be a bit of an undertaking to enable it, but I would highly recommend we do.

Suggested change
export function getPlaceholder(arg: Pick<MethodArg, 'type' | 'components'>): string {
export function getPlaceholder(arg: Pick<MethodArg, 'type' | 'components'>): string | null {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good one. And agree on the strict mode!

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
@spalladino
Copy link
Contributor Author

@frangio updated!

@@ -137,5 +146,6 @@ export function callDescription(method: any, args: string[]): string {
export default {
buildCallData,
getABIFunction,
getABIType: getArgTypeLabel,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we remove this here? It didn't exist before this PR so there are no backwards compatibility issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that was the auto-rename backfiring - sorry about it

@spalladino
Copy link
Contributor Author

@frangio updated!

Copy link
Contributor

@frangio frangio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🚀

@frangio frangio added the status:ready-to-merge Order mergify to merge label Dec 17, 2019
@mergify mergify bot merged commit e3d1960 into master Dec 17, 2019
@mergify mergify bot deleted the feature/support-tuples-input-#1330 branch December 17, 2019 20:35
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status:ready-to-merge Order mergify to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support tuples in interactive commands
2 participants